package jsoner

import (
	"sync"
	"sync/atomic"

	jsoniter "github.com/json-iterator/go"
)

type JsonerAPI interface {
	// Marshal adapts to json/encoding Marshal API
	// Refer to https://godoc.org/encoding/json#Marshal for more information
	Marshal(v any) ([]byte, error)
	// MarshalWithoutEscape EscapeHTML => false
	MarshalWithoutEscape(v any) ([]byte, error)
	// MarshalToString convenient method to write as string instead of []byte
	MarshalToString(v any) (string, error)
	// MarshalToStringWithoutEscape convenient method to write as string instead of []byte
	MarshalToStringWithoutEscape(v any) (string, error)
	// Unmarshal adapts to json/encoding Unmarshal API
	// Refer to https://godoc.org/encoding/json#Unmarshal for more information
	Unmarshal(data []byte, v any) error
	// UnmarshalFromString is a convenient method to read from string instead of []byte
	UnmarshalFromString(str string, v any) error
	// Valid reports whether data is a valid JSON encoding
	Valid(v []byte) bool
}

// jsonerLib 包装 JsonerAPI 的结构体，以实现原子操作，便于切换json库
type jsonerLib struct {
	lib JsonerAPI
}

var (
	oJsonIterator = &jsonerLib{&jsonIterator{
		// ConfigCompatibleWithStandardLibrary tries to be 100% compatible with standard library behavior
		lib: jsoniter.ConfigCompatibleWithStandardLibrary,
		// ConfigCompatibleWithStandardLibrary And EscapeHTML => false
		libUnEscape: jsoniter.Config{
			EscapeHTML:             false,
			SortMapKeys:            true,
			ValidateJsonRawMessage: true,
		}.Froze()}}
	oJsonStandard = &jsonerLib{&jsonStandard{}}
	oDefaultLib   atomic.Pointer[jsonerLib] // default jsoner is jsoniter
	oDefaultOnce  sync.Once
)

func defaultLib() JsonerAPI {
	oDefaultOnce.Do(func() {
		oDefaultLib.Store(oJsonIterator)
	})
	return oDefaultLib.Load().lib
}

// 切换Json库为 Json StandardLibrary 标准库
func UseStandardLibrary() {
	oDefaultLib.Store(oJsonStandard)
}

// 切换Json库为 Json Iterator 库
func UseJsonIterator() {
	oDefaultLib.Store(oJsonIterator)
}

// 切换Json库为 自定义 Jsoner
func SetJsoner(lib JsonerAPI) {
	if lib == nil {
		return
	}
	oDefaultLib.Store(&jsonerLib{lib})
}

// Marshal adapts to json/encoding Marshal API
// Refer to https://godoc.org/encoding/json#Marshal for more information
func Marshal(v any) ([]byte, error) {
	return defaultLib().Marshal(v)
}

// MarshalWithoutEscape EscapeHTML => false
func MarshalWithoutEscape(v any) ([]byte, error) {
	return defaultLib().MarshalWithoutEscape(v)
}

// MarshalToString convenient method to write as string instead of []byte
func MarshalToString(v any) (string, error) {
	return defaultLib().MarshalToString(v)
}

// MarshalToStringWithoutEscape convenient method to write as string instead of []byte
func MarshalToStringWithoutEscape(v any) (string, error) {
	return defaultLib().MarshalToStringWithoutEscape(v)
}

// Unmarshal adapts to json/encoding Unmarshal API
// Refer to https://godoc.org/encoding/json#Unmarshal for more information
func Unmarshal(data []byte, v any) error {
	return defaultLib().Unmarshal(data, v)
}

func UnmarshalFromString(str string, v any) error {
	return defaultLib().UnmarshalFromString(str, v)
}

// Valid reports whether data is a valid JSON encoding
func Valid(v []byte) bool {
	return defaultLib().Valid(v)
}
